package com.huawei.java.alogrithm;

import com.huawei.java.model.ResultHandle;
import com.huawei.java.model.*;

import java.util.*;

public class UsedThresholdAlgorithm {
    public Graph graph;

    // 按照用户节点可以达到的边缘节点数量进行排序，能达到边缘节点数少的优先分配
    public TreeSet<ClientNode> clientNodeTreeSet;

    public List<Demand> demands;

    // key 用户 Map<String, Integer> 每个边缘节点给客户分配的带宽
    private final Map<String, Map<String, Integer>> allocationMaps = new HashMap<>();

    // 次数使用超过五次就踢出出set 边缘节点能达到用户数比较少的优先拉满这个边缘节点
    private TreeSet<SiteNode> siteNodeSet = new TreeSet<>(new Comparator<SiteNode>() {
        @Override
        public int compare(SiteNode oneSite, SiteNode anotherSite) {
            if (oneSite.getCurrentBandwidth() != oneSite.getTotalBandwidth()) {
                return -1;
            }
            if (anotherSite.getCurrentBandwidth() != anotherSite.getTotalBandwidth()) {
                return 1;
            }
            int result = oneSite.getValidClient().size() - anotherSite.getValidClient().size();
            return result == 0 ? 1 : result;
        }
    });

    public UsedThresholdAlgorithm(Graph graph, TreeSet<ClientNode> clientNodeTreeSet, List<Demand> demands) {
        this.graph = graph;
        this.clientNodeTreeSet = clientNodeTreeSet;
        this.demands = demands;
    }

    public void process(Demand demand) {
        // 重新刷新结果集和带宽
        reloadBandwidth();
        Map<String, Integer> demandMap = demand.getDemandMap();
        boolean success = true;
        for (ClientNode clientNode : clientNodeTreeSet) {
            int clientDemandBandwidth = demandMap.get(clientNode.getName());
            List<SiteNode> validSiteNodes = clientNode.getValidSiteNodes();
            ThresholdDistributionResult result = thresholdDistribution(clientDemandBandwidth, validSiteNodes);
            if (result.clientDemandBandwidth > 0) {
                demand.setDistributionSuccess(false);
                success = false;
                break;
            }
            Integer all = 0;
            for (Map.Entry<String, Integer> entry : result.allocationMap.entrySet()) {
                if (entry.getValue() > graph.getSiteIdMap().get(entry.getKey()).getTotalBandwidth())
                    System.out.println(clientNode.getName() + "erorrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr");
                all += entry.getValue();
            }

            if (!all.equals(demandMap.get(clientNode.getName()))) {
                System.out.println(clientNode.getName() + "erorrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr");
            }
            allocationMaps.put(clientNode.getName(), result.allocationMap);
        }
        // 说明这次分配失败
        if (!success) {
            return;
        }
        demand.setDistributionSuccess(true);
        graph.getSiteNodes().forEach(siteNode -> {
            if (siteNode.getCurrentBandwidth() != siteNode.getTotalBandwidth()) {
                siteNode.setAvailableNum(siteNode.getAvailableNum() - 1);
            }
        });
        //HashMap<String, Map<String, Integer>> newAllocationMaps = redistribution(allocationMaps, demand);
        ResultCompute.store(new HashMap<>(allocationMaps));
        ResultCompute.compute();
        // 记录历次分配的结果
        TimestampResult timestampResult = new TimestampResult(demand.getTimestamp(), new HashMap<>(allocationMaps));
        ResultHandle.timestampResults.add(timestampResult);
        // 如果提前退出了，每个站点都分配完成五次或者出现分配不了的时候
    }



    private ThresholdDistributionResult thresholdDistribution(int clientDemandBandwidth, List<SiteNode> sites) {
        HashMap<String, Integer> allocationMap = new HashMap<>();
        HashSet<String> exitsSites = new HashSet<>();
        while (clientDemandBandwidth > 0) {
            SiteNode siteNode = sites.stream().filter(site -> site.getCurrentBandwidth() > 0 && !exitsSites.contains(site.getName()))
                    .min(Comparator.comparing(SiteNode::isUsed).reversed().thenComparing(SiteNode::existUsedCount)).get();
            if (siteNode.getAvailableNum() == 0) {
                //
            } else {
                int currentBandwidth = siteNode.getCurrentBandwidth();
                if (currentBandwidth >= clientDemandBandwidth) {
                    siteNode.setCurrentBandwidth(currentBandwidth - clientDemandBandwidth);
                    allocationMap.put(siteNode.getName(), clientDemandBandwidth);
                    clientDemandBandwidth = 0;
                    break;
                }
                // 把当前节点的流量都分配给他，并且这次分配完了之后 阈值次数减一
                siteNode.setCurrentBandwidth(0);
                allocationMap.put(siteNode.getName(), currentBandwidth);
                // 用户还需要多少带宽
                clientDemandBandwidth -= currentBandwidth;
            }
            exitsSites.add(siteNode.getName());
        }


        return new ThresholdDistributionResult(clientDemandBandwidth, allocationMap);
    }

    static class ThresholdDistributionResult {
        int clientDemandBandwidth;

        HashMap<String, Integer> allocationMap;

        public ThresholdDistributionResult(int clientDemandBandwidth, HashMap<String, Integer> allocationMap) {
            this.clientDemandBandwidth = clientDemandBandwidth;
            this.allocationMap = allocationMap;
        }
    }

    private void reloadBandwidth() {
        for (SiteNode siteNode : graph.getSiteNodes()) {
            siteNode.setCurrentBandwidth(siteNode.getTotalBandwidth());
        }
        allocationMaps.clear();
    }

}
